using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using SBPweb.Themes.Windows.Skins;
using System.Windows.Forms;
using System.Drawing;
using SBPweb.Themes.Windows;

namespace SBPweb.Controls.Windows.Editors
{
	/// <summary>
	/// Class of ComboBox
	/// </summary>
	[ToolboxBitmap(typeof(System.Windows.Forms.ComboBox))]
	public partial class ComboBox : System.Windows.Forms.ComboBox, ISkinnable
	{
		#region Private members

		private const int MINIMUM_BUTTON_WIDTH = 18;// minimum width of the combobutton area

		private bool mUseDefaultSkin = true;

		private SBPweb.Themes.Windows.Skins.Size mMinSize;
		private Margin mSizingMargin;
		private Margin mContentMargin;
		private Border mPopupFormBorder;
		private Margin mBorderThin;
		private Color mBackColor;
		
		private int buttonLeft;
		private int buttonTop;
		private int buttonVisibleWidth;
		private int buttonVisibleHeight;

		private Skin mSkin;
		private MouseEventState mMState = MouseEventState.None;

		private Color mNoSkinBackColor;
		private Color mNoSkinForeColor;

		#endregion

		#region Constructor logic

		public ComboBox()
		{
			mNoSkinBackColor = BackColor;
			mNoSkinForeColor = ForeColor;

			InitializeComponent();

			InitializeBorder();
			InitializeMargins();
			InitializeMinSize();
			InitializeBackColor();

			SetStyle();
			RegisterEventHandlers();
			base.EnabledChanged += new EventHandler(ComboBox_EnabledChanged);
			
		}

		void ComboBox_EnabledChanged(object sender, EventArgs e)
		{
			if (!this.Enabled)
			{
				this.BackColor = Color.White;
			}
		}

		public ComboBox(Skin skin)
			: base()
		{
			mSkin = skin;

		}
		private void SetStyle()
		{
			this.SetStyle(ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer | /*ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint |*/ ControlStyles.SupportsTransparentBackColor, true);
		}

		private void RegisterEventHandlers()
		{
			this.MouseEnter += new EventHandler(this_MouseEnter);
			this.MouseLeave += new EventHandler(this_MouseLeave);
			this.MouseDown += new MouseEventHandler(this_MouseDown);
			this.MouseUp += new MouseEventHandler(this_MouseUp);
			this.MouseHover += new EventHandler(this_MouseHover);
			//this.DrawMode = DrawMode.OwnerDrawFixed;
			//this.DrawItem += new DrawItemEventHandler(ComboBox_DrawItem);
			DefaultLookAndFeel.OnSkinChanged += new EventHandler(DefaultLookAndFeel_OnSkinChanged);
		}


		void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
		{
			Pen p = new Pen(Color.Red);
			
			e.Graphics.DrawRectangle(p, e.Bounds.X - 1, e.Bounds.Y - 1, e.Bounds.Right + 1, e.Bounds.Bottom + 1);
			
			//e.DrawFocusRectangle();
		}

		/*public new bool Enabled
		{
			get
			{
				return mEnabled;
			}
			set
			{
				mEnabled = value;
				//this.DrawMode = (mEnabled)? DrawMode.Normal:DrawMode.OwnerDrawFixed;
				mMState = (mEnabled)? MouseEventState.None : MouseEventState.OnDisabledDown;
			}
		}*/
		

		

		#endregion

		#region Custom draw

		const int WM_PAINT = 0x000F;
		const int WM_ERASEBKGND = 0x0014;
		//const int WM_DRAWITEM = 0x002B;

		protected override void WndProc(ref Message m)
		{
			base.WndProc(ref m);

			if (m.Msg == WM_PAINT)
			{
				InvokePaint(this, new PaintEventArgs(this.CreateGraphics(), this.ClientRectangle));
			}
			if (m.Msg == WM_ERASEBKGND)
			{ 
				InvokePaintBackground(this, new PaintEventArgs(this.CreateGraphics(), this.ClientRectangle));
			}
		}

		protected override void OnEnabledChanged(EventArgs e)
		{
				base.OnEnabledChanged(e);
				if (this.Enabled)
				{
					this.BackColor = Color.White;
				}
		}

		protected override void OnDrawItem(DrawItemEventArgs e)
		{
			//if (this.Enabled)
		}


		protected override void OnPaint(PaintEventArgs e)
		{
			
			if (Skin == null && (!UseDefaultSkin || DefaultLookAndFeel.Skin == null))
			{
				
				base.OnPaint(e);
				
				return;
			}

			OnPaintBackground(e);
			

			Rectangle rect;
			rect = new Rectangle(e.ClipRectangle.Location, e.ClipRectangle.Size);
			rect.Width -= 1;
			rect.Height -= 1;

			if (this.Enabled)
			{
				e.Graphics.DrawRectangle(new Pen(mPopupFormBorder.AllColor, mBorderThin.All), rect);
			}
			//else
			//{
			//    e.Graphics.FillRectangle(new SolidBrush(Color.Red), rect);
			//}

			mMState = (this.Enabled) ? MouseEventState.None : MouseEventState.OnDisabledDown;
			
			DrawComboButton(e, rect.Width, rect.Height);
		}

		private void DrawComboButton(PaintEventArgs e, int width, int height)
		{
			System.Drawing.Image img = Skin.GetImageFromBitmapResource(Skin.KeyPrefix + "editors.combobutton.png");
			bool verticalLayout = false;
			if (Skin.CachedProperties.ComboButtonLayout == LayoutDirection.Vertical) verticalLayout = true;

			int imgCount = 4;
			int imgWidth;
			int imgHeight;
			int imgLeft = 0;
			int imgTop = 0;

			if (!verticalLayout)
			{
				imgWidth = (Int32)(img.Width / imgCount);
				imgHeight = img.Height - 1;

				if (!this.Enabled)
				{
					imgLeft = 3 * imgWidth;
				}
				else
				{
					switch (mMState)
					{
						default:
						case MouseEventState.None:
							imgLeft = 0;
							break;
						case MouseEventState.OnHover:
							imgLeft = 1 * imgWidth;
							break;
						case MouseEventState.OnDown:
							imgLeft = 2 * imgWidth;
							break;
						case MouseEventState.OnDisabledDown:
							imgLeft = 3 * imgWidth;
							break;
					}
				}
			}
			else
			{
				imgWidth = img.Width - 1;
				imgHeight = (Int32)(img.Height / imgCount);

				if (!this.Enabled)
				{
					imgTop = 3 * imgHeight;
				}
				else
				{
					switch (mMState)
					{
						default:
						case MouseEventState.None:
							imgTop = 0;
							break;
						case MouseEventState.OnHover:
							imgTop = 1 * imgHeight;
							break;
						case MouseEventState.OnDown:
							imgTop = 2 * imgHeight;
							break;
						case MouseEventState.OnDisabledDown:
							imgTop = 3 * imgHeight;
							break;
					}
				}
			}

			#region Image parts
			Rectangle iLT = new Rectangle(imgLeft, imgTop, mSizingMargin.Left, mSizingMargin.Top);
			Rectangle iT = new Rectangle(imgLeft + mSizingMargin.Left, imgTop, imgWidth - mSizingMargin.Horizontal, mSizingMargin.Top);
			Rectangle iRT = new Rectangle(imgLeft + imgWidth - mSizingMargin.Right, imgTop, mSizingMargin.Right, mSizingMargin.Top);
			Rectangle iLM = new Rectangle(imgLeft, imgTop + mSizingMargin.Top, mSizingMargin.Left, imgHeight - mSizingMargin.Vertical);
			Rectangle iM = new Rectangle(imgLeft + mSizingMargin.Left, imgTop + mSizingMargin.Top, imgWidth - mSizingMargin.Horizontal, imgHeight - mSizingMargin.Vertical);
			Rectangle iRM = new Rectangle(imgLeft + imgWidth - mSizingMargin.Right, imgTop + mSizingMargin.Top, mSizingMargin.Right, imgHeight - mSizingMargin.Vertical);
			Rectangle iLB = new Rectangle(imgLeft, imgTop + imgHeight - mSizingMargin.Bottom, mSizingMargin.Left, mSizingMargin.Bottom);
			Rectangle iB = new Rectangle(imgLeft + mSizingMargin.Left, imgTop + imgHeight - mSizingMargin.Bottom, imgWidth - mSizingMargin.Horizontal, mSizingMargin.Bottom);
			Rectangle iRB = new Rectangle(imgLeft + imgWidth - mSizingMargin.Right, imgTop + imgHeight - mSizingMargin.Bottom, mSizingMargin.Right, mSizingMargin.Bottom);
			#endregion

			if (imgWidth > MINIMUM_BUTTON_WIDTH)
				imgWidth = MINIMUM_BUTTON_WIDTH; //minimum width of the combobutton area
			if (imgHeight > height - 1)
				imgHeight = height - 1 ; // minimum height of the combobutton area  

			buttonLeft = width - imgWidth - 1;
			buttonTop = 1;
			buttonVisibleWidth = imgWidth +1;
			buttonVisibleHeight = imgHeight;

			#region Window parts
			Rectangle tLT = new Rectangle(buttonLeft, buttonTop, mSizingMargin.Left, mSizingMargin.Top);
			Rectangle tT = new Rectangle(buttonLeft + mSizingMargin.Left, buttonTop, imgWidth - mSizingMargin.Horizontal, mSizingMargin.Top);
			Rectangle tRT = new Rectangle(buttonLeft + imgWidth - mSizingMargin.Right, buttonTop, mSizingMargin.Right, mSizingMargin.Top);
			Rectangle tLM = new Rectangle(buttonLeft, buttonTop + mSizingMargin.Top, mSizingMargin.Left, imgHeight - mSizingMargin.Vertical);
			Rectangle tM = new Rectangle(buttonLeft + mSizingMargin.Left, buttonTop + mSizingMargin.Top, imgWidth - mSizingMargin.Horizontal, imgHeight - mSizingMargin.Vertical);
			Rectangle tRM = new Rectangle(buttonLeft + imgWidth - mSizingMargin.Right, buttonTop + mSizingMargin.Top, mSizingMargin.Right, imgHeight - mSizingMargin.Vertical);
			Rectangle tLB = new Rectangle(buttonLeft, buttonTop + imgHeight - mSizingMargin.Bottom, mSizingMargin.Left, mSizingMargin.Bottom);
			Rectangle tB = new Rectangle(buttonLeft + mSizingMargin.Left, buttonTop + imgHeight - mSizingMargin.Bottom, imgWidth - mSizingMargin.Horizontal, mSizingMargin.Bottom);
			Rectangle tRB = new Rectangle(buttonLeft + imgWidth - mSizingMargin.Right, buttonTop + imgHeight - mSizingMargin.Bottom, mSizingMargin.Right, mSizingMargin.Bottom);
			#endregion

			#region Drawing
			e.Graphics.DrawImage(img, tLT, iLT, GraphicsUnit.Pixel);
			e.Graphics.DrawImage(img, tT, iT, GraphicsUnit.Pixel);
			e.Graphics.DrawImage(img, tRT, iRT, GraphicsUnit.Pixel);
			e.Graphics.DrawImage(img, tLM, iLM, GraphicsUnit.Pixel);
			e.Graphics.DrawImage(img, tM, iM, GraphicsUnit.Pixel);
			e.Graphics.DrawImage(img, tRM, iRM, GraphicsUnit.Pixel);
			e.Graphics.DrawImage(img, tLB, iLB, GraphicsUnit.Pixel);
			e.Graphics.DrawImage(img, tB, iB, GraphicsUnit.Pixel);
			e.Graphics.DrawImage(img, tRB, iRB, GraphicsUnit.Pixel);
			#endregion

			DrawGlyph(e, buttonLeft, buttonTop, imgWidth, imgHeight);
		}


		private void DrawGlyph(PaintEventArgs e, int leftOffset, int topOffset, int buttonWidth, int buttonHeight)
		{
			System.Drawing.Image img = Skin.GetImageFromBitmapResource(Skin.KeyPrefix + "editors.combobutton_glyph.png");
			bool verticalLayout = false;
			if (Skin.CachedProperties.ComboGlyphLayout == LayoutDirection.Vertical) verticalLayout = true;

			int imgCount = 4;
			int imgWidth;
			int imgHeight;
			int imgTop;
			int imgLeft;

			if (!verticalLayout)
			{
				imgWidth = (Int32)(img.Width / imgCount);
				imgHeight = img.Height - 1;
				imgTop = 0;

				if (!this.Enabled)
				{
					imgLeft = 3 * imgWidth;
				}
				else
				{
					switch (mMState)
					{
						default:
						case MouseEventState.None:
							imgLeft = 0;
							break;
						case MouseEventState.OnHover:
							imgLeft = 1 * imgWidth;
							break;
						case MouseEventState.OnDown:
							imgLeft = 2 * imgWidth;
							break;
						case MouseEventState.OnDisabledDown:
							imgLeft = 3 * imgWidth;
							break;
					}
				}
			}
			else
			{
				imgWidth = img.Width;
				imgHeight = (Int32)(img.Height / imgCount);
				imgLeft = 0;

				if (!this.Enabled)
				{
					imgTop = 3 * imgHeight;
				}
				else
				{
					switch (mMState)
					{
						default:
						case MouseEventState.None:
							imgTop = 0;
							break;
						case MouseEventState.OnHover:
							imgTop = 1 * imgHeight;
							break;
						case MouseEventState.OnDown:
							imgTop = 2 * imgHeight;
							break;
						case MouseEventState.OnDisabledDown:
							imgTop = 3 * imgHeight;
							break;
					}
				}
			}

			Rectangle rect = new Rectangle(imgLeft, imgTop, imgWidth, imgHeight);
			e.Graphics.DrawImage(img, leftOffset + (float)Math.Round((buttonWidth - imgWidth) / 2.0,MidpointRounding.AwayFromZero), topOffset + (float)Math.Round((buttonHeight - imgHeight) / 2.0, MidpointRounding.AwayFromZero), rect, GraphicsUnit.Pixel);
			//this.MinimumSize = new System.Drawing.Size((int)mMinSize.MinSize.Width, (int)mMinSize.MinSize.Height);
		}

		private void InitializeMargins()
		{
			if (Skin == null)
			{
				mSizingMargin = new Margin();
				mContentMargin = new Margin();
			}
			else
			{
				mSizingMargin = Skin.CachedProperties.ComboSizingMargin;
				mContentMargin = Skin.CachedProperties.ComboContentMargin;

			}
		}

		private void InitializeMinSize()
		{
			if (Skin == null)
			{
				mMinSize = new SBPweb.Themes.Windows.Skins.Size();
			}
			else
			{
				mMinSize = Skin.CachedProperties.ComboMinSize;
			}
		}

		private void InitializeBorder()
		{
			if (Skin == null)
			{
				mPopupFormBorder = new Border();
				mBorderThin = new Margin();
			}
			else
			{
				mPopupFormBorder = Skin.CachedProperties.ComboPopupFormBorder;
				mBorderThin = Skin.CachedProperties.ComboBorderThin;

			}
		}

		private void InitializeBackColor()
		{
			if (Skin != null)
			{
				//mBackColor = new Colors(Skin.CachedProperties.ControlColor, Skin.CachedProperties.ControlTextColor);
				mBackColor = Skin.CachedProperties.ComboBackColor;
		
			}
		}

		protected override void OnPaintBackground(PaintEventArgs e)
		{
			//base.OnPaintBackground(e);
			if (Skin != null )
			{
				if (this.Enabled)
				{
					//this.BackColor = mBackColor;
					//this.ForeColor = Color.Black;
					this.BackColor = Skin.CachedProperties.ControlColor;
					this.ForeColor = Skin.CachedProperties.ControlTextColor;
				}
				else
				{
					//this.BackColor = Color.White;
					//this.ForeColor = Color.White;
					this.BackColor = Skin.CachedProperties.ControlDisabledColor;
					this.ForeColor = Skin.CachedProperties.ControlDisabledTextColor;
				}
				
			}
			else
			{
				// this.BackColor = Color.White;
				this.BackColor = mNoSkinBackColor;
				this.ForeColor = mNoSkinForeColor;
			}
		}

		#endregion

		#region Events
		

		void this_MouseEnter(object sender, EventArgs e)
		{
			if (mMState != MouseEventState.OnDisabledDown)
			{
				mMState = MouseEventState.OnHover;
			}
			this.Invalidate();
		}

		void this_MouseUp(object sender, MouseEventArgs e)
		{
			if (mMState != MouseEventState.OnDisabledDown)
			{
				if (e.X < buttonLeft || e.X > buttonVisibleWidth || e.Y < buttonTop || e.Y > buttonVisibleHeight)
				{
					mMState = MouseEventState.None;
				}
				else
				{
					mMState = MouseEventState.OnHover;
				}
			}
			this.Invalidate();
		}

		void this_MouseDown(object sender, MouseEventArgs e)
		{
			if (mMState != MouseEventState.OnDisabledDown)
			{
				mMState = MouseEventState.OnDown;
			}
			this.Invalidate();
		}

		void this_MouseLeave(object sender, EventArgs e)
		{
			if (mMState != MouseEventState.OnDisabledDown)
			{
				mMState = MouseEventState.None;
			}
			this.Invalidate();
		}

		void this_MouseHover(object sender, EventArgs e)
		{
			if (mMState != MouseEventState.OnDisabledDown)
			{
				mMState = MouseEventState.OnHover;
			}
		}


		void DefaultLookAndFeel_OnSkinChanged(object sender, EventArgs e)
		{
			InitializeMargins();
			InitializeMinSize();
			InitializeBorder();
			InitializeBackColor();

			this.BackColor = mBackColor;
			this.Invalidate(true);
		}

		#endregion


		#region ISkinnable Members

		/// <summary>
		/// Use default skin?
		/// </summary>
		[Category("Look && feel")]
		public bool UseDefaultSkin
		{
			get
			{
				return mUseDefaultSkin;
			}
			set
			{
				mUseDefaultSkin = value;
				Skin = DefaultLookAndFeel.Skin;
				Invalidate();
			}
		}

		/// <summary>
		/// Used skin
		/// </summary>
		[Category("Look && feel")]
		public Skin Skin
		{
			get
			{
				if (this.UseDefaultSkin)
				{
					return DefaultLookAndFeel.Skin;
				}
				else
				{
					return mSkin;
				}
			}
			set
			{
				mSkin = value;
				Invalidate();
			}
		}

		#endregion
	}
}
